package org.eclipse.paho.android.sample.activity;


import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.widget.Toast;

import org.eclipse.paho.android.sample.R;
import org.eclipse.paho.android.sample.event.CancelPublishLocationEvent;
import org.eclipse.paho.android.sample.event.PublishLocationEvent;
import org.eclipse.paho.android.sample.event.SendLocationEvent;
import org.eclipse.paho.android.sample.internal.Connections;
import org.eclipse.paho.android.sample.model.ConnectionModel;
import org.eclipse.paho.android.sample.utils.LocationUtils;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;


public class MainActivity extends AppCompatActivity implements FragmentDrawer.FragmentDrawerListener {

    private FragmentDrawer drawerFragment;

    private static final String TAG = "MainActivity";

    private final ChangeListener changeListener = new ChangeListener();

    private final MainActivity mainActivity = this;

    private ArrayList<String> connectionMap;

    //  定位
    private LocationManager locationManager;
    private Location newLocation;
    private String locationProvider;
    private static boolean flag = true;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);

        drawerFragment = (FragmentDrawer) getSupportFragmentManager().findFragmentById(R.id.fragment_navigation_drawer);
        drawerFragment.setUp(R.id.fragment_navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), mToolbar);
        drawerFragment.setDrawerListener(this);

        populateConnectionList();

        //  经纬度 start
        locationManager = (LocationManager) getSystemService(getApplicationContext().LOCATION_SERVICE);
        EventBus.getDefault().register(this);
    }
    /**
     * LocationListern监听器
     * 参数：地理位置提供器、监听位置变化的时间间隔、位置变化的距离间隔、LocationListener监听器
     */

    LocationListener locationListener = new LocationListener() {

        @Override
        public void onStatusChanged(String provider, int status, Bundle arg2) {

        }

        @Override
        public void onProviderEnabled(String provider) {
            Log.d(TAG, "onProviderEnabled: " + provider + ".." + Thread.currentThread().getName());
        }

        @Override
        public void onProviderDisabled(String provider) {
            Log.d(TAG, "onProviderDisabled: " + provider + ".." + Thread.currentThread().getName());
        }

        @Override
        public void onLocationChanged(Location location) {
            newLocation = location;
            Log.d(TAG, "onLocationChanged: " + ".." + Thread.currentThread().getName());
            //如果位置发生变化,重新显示
            showLocation(location);
        }
    };

    private void showLocation(Location location) {
        Log.d(TAG,"定位成功------->"+"location------>经度为：" + location.getLatitude() + "\n纬度为" + location.getLongitude());
        /*if(publishLocationTimer == null){
            publishLocationTimer = new Timer();
            publishLocationTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    EventBus.getDefault().post(new SendLocationEvent(newLocation.getLatitude(),newLocation.getLongitude()));
                }
            }, 0, 10 * 1000);//  10秒发送一次
        }else{
            EventBus.getDefault().post(new SendLocationEvent(newLocation.getLatitude(),newLocation.getLongitude()));
        }*/
        EventBus.getDefault().post(new SendLocationEvent(location.getLatitude(),location.getLongitude()));

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(PublishLocationEvent event) {
        Log.d(TAG, "准备开始上报经纬度");
        if (flag) {
            Criteria criteria = new Criteria();
            criteria.setAccuracy(Criteria.ACCURACY_COARSE);//低精度，如果设置为高精度，依然获取不了location。
            criteria.setAltitudeRequired(false);//不要求海拔
            criteria.setBearingRequired(false);//不要求方位
            criteria.setCostAllowed(true);//允许有花费
            criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗

            //从可用的位置提供器中，匹配以上标准的最佳提供器
            locationProvider = locationManager.getBestProvider(criteria, true);
            if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "没有定位权限:GPS、NETWORK ");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
                return;
            }
            Location location = locationManager.getLastKnownLocation(locationProvider);
            Log.d(TAG, "上一次定位信息" + (location == null) + "..");
            if (location != null) {
                Log.d(TAG, "当前经纬度为：");
                //不为空,显示地理位置经纬度
                showLocation(location);
            }
            //监视地理位置变化
            locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);
            flag = false;
        }else{
            Location location = locationManager.getLastKnownLocation(locationProvider);
            showLocation(location);
        }
    }

    /*@Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessageEvent(CancelPublishLocationEvent event) {
        publishLocationTimer.cancel();
    }*/
    public void removeConnectionRow(Connection connection) {
        drawerFragment.removeConnection(connection);
        populateConnectionList();
    }


    private void populateConnectionList() {
        // Clear drawerFragment
        drawerFragment.clearConnections();

        // get all the available connections
        Map<String, Connection> connections = Connections.getInstance(this)
                .getConnections();
        int connectionIndex = 0;
        connectionMap = new ArrayList<String>();

        Iterator connectionIterator = connections.entrySet().iterator();
        while (connectionIterator.hasNext()) {
            Map.Entry pair = (Map.Entry) connectionIterator.next();
            drawerFragment.addConnection((Connection) pair.getValue());
            connectionMap.add((String) pair.getKey());
            ++connectionIndex;
        }

        if (connectionMap.size() == 0) {
            displayView(-1);
        } else {
            displayView(0);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }


    @Override
    public void onDrawerItemSelected(int position) {
        displayView(position);
    }

    @Override
    public void onDrawerItemLongSelected(int position) {
        displayDeleteView(position);
    }

    @Override
    public void onAddConnectionSelected() {
        Fragment editConnectionFragment = new EditConnectionFragment();
        String title = "Edit Connection";
        displayFragment(editConnectionFragment, title);
    }

    @Override
    public void onHelpSelected() {
        Fragment helpFragment = new HelpFragment();
        displayFragment(helpFragment, getString(R.string.help_and_feedback));

    }

    private void displayDeleteView(int position) {
        if (position == -1) {
            displayFragment(new HomeFragment(), "Home");
        } else {
            Fragment fragment = new ManageConnectionFragment();
            Bundle bundle = new Bundle();
            bundle.putString(ActivityConstants.CONNECTION_KEY, connectionMap.get(position));
            fragment.setArguments(bundle);
            Map<String, Connection> connections = Connections.getInstance(this)
                    .getConnections();
            Connection connection = connections.get(connectionMap.get(position));
            displayFragment(fragment, "");
        }
    }

    private void displayView(int position) {
        if (position == -1) {
            displayFragment(new HomeFragment(), "Home");
        } else {
            Fragment fragment = new ConnectionFragment();
            Bundle bundle = new Bundle();
            bundle.putString(ActivityConstants.CONNECTION_KEY, connectionMap.get(position));
            fragment.setArguments(bundle);
            Map<String, Connection> connections = Connections.getInstance(this)
                    .getConnections();
            Connection connection = connections.get(connectionMap.get(position));
            String title = connection.getId();
            displayFragment(fragment, title);
        }
    }

    private void displayFragment(Fragment fragment, String title) {
        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(R.id.container_body, fragment);
            fragmentTransaction.commit();

            // Set Toolbar Title
            getSupportActionBar().setTitle(title);


        }
    }

    public void updateAndConnect(ConnectionModel model) {
        Map<String, Connection> connections = Connections.getInstance(this)
                .getConnections();

        Log.i(TAG, "Updating connection: " + connections.keySet().toString());
        try {
            Connection connection = connections.get(model.getClientHandle());
            // First disconnect the current instance of this connection
            if (connection.isConnected()) {
                connection.changeConnectionStatus(Connection.ConnectionStatus.DISCONNECTING);
                connection.getClient().disconnect();
            }
            //  保存 设备密钥
            connection.setDeviceSecret(model.getDeviceSecret());
            String t = System.currentTimeMillis()+"";
            String newClientId = "AndroidExampleClient" + "|securemode=2,signmethod=hmacsha1,timestamp=" + t + "|";
            model.setClientId(newClientId);
            model.setPassword(model.createpwd(t));
            // Update the connection.
            connection.updateConnection(model.getClientId(), model.getServerHostName(), model.getServerPort(), model.isTlsConnection());
            connection.changeConnectionStatus(Connection.ConnectionStatus.CONNECTING);



            String[] actionArgs = new String[1];
            actionArgs[0] = model.getClientId();
            final ActionListener callback = new ActionListener(this,
                    ActionListener.Action.CONNECT, connection, actionArgs);
            connection.getClient().setCallback(new MqttCallbackHandler(this, model.getClientHandle()));

            connection.getClient().setTraceCallback(new MqttTraceCallback());
            MqttConnectOptions connOpts = optionsFromModel(model);
            connection.addConnectionOptions(connOpts);
            Connections.getInstance(this).updateConnection(connection);
            drawerFragment.updateConnection(connection);

            connection.getClient().connect(connOpts, null, callback);
            Fragment fragment = new ConnectionFragment();
            Bundle bundle = new Bundle();
            bundle.putString(ActivityConstants.CONNECTION_KEY, connection.handle());
            fragment.setArguments(bundle);
            String title = connection.getId();
            displayFragment(fragment, title);


        } catch (MqttException ex) {
            Log.e(TAG, "Exception occurred updating connection: " + connections.keySet().toString() + " : " + ex.getMessage());
        }
    }


    /**
     * Takes a {@link ConnectionModel} and uses it to connect
     * and then persist.
     *
     * @param model - The connection Model
     */
    public void persistAndConnect(ConnectionModel model) {
        Log.i(TAG, "Persisting new connection:" + model.getClientHandle());
        Connection connection = Connection.createConnection(model.getClientHandle(), model.getClientId(), model.getServerHostName(), model.getServerPort(), this, model.isTlsConnection());
        connection.registerChangeListener(changeListener);
        connection.changeConnectionStatus(Connection.ConnectionStatus.CONNECTING);


        String[] actionArgs = new String[1];
        actionArgs[0] = model.getClientId();
        final ActionListener callback = new ActionListener(this,
                ActionListener.Action.CONNECT, connection, actionArgs);
        connection.getClient().setCallback(new MqttCallbackHandler(this, model.getClientHandle()));


        connection.getClient().setTraceCallback(new MqttTraceCallback());

        MqttConnectOptions connOpts = optionsFromModel(model);

        connection.addConnectionOptions(connOpts);
        Connections.getInstance(this).addConnection(connection);
        connectionMap.add(model.getClientHandle());
        drawerFragment.addConnection(connection);

        try {
            connection.getClient().connect(connOpts, null, callback);
            Fragment fragment = new ConnectionFragment();
            Bundle bundle = new Bundle();
            bundle.putString(ActivityConstants.CONNECTION_KEY, connection.handle());
            bundle.putBoolean(ActivityConstants.CONNECTED, true);
            fragment.setArguments(bundle);
            String title = connection.getId();
            displayFragment(fragment, title);

        } catch (MqttException e) {
            Log.e(this.getClass().getCanonicalName(),
                    "MqttException occurred", e);
        }

    }


    private MqttConnectOptions optionsFromModel(ConnectionModel model) {

        MqttConnectOptions connOpts = new MqttConnectOptions();
        connOpts.setCleanSession(model.isCleanSession());
        connOpts.setConnectionTimeout(model.getTimeout());
        connOpts.setKeepAliveInterval(model.getKeepAlive());
        if (!model.getUsername().equals(ActivityConstants.empty)) {
            connOpts.setUserName(model.getUsername());
        }

        if (!model.getPassword().equals(ActivityConstants.empty)) {
            connOpts.setPassword(model.getPassword().toCharArray());
        }
        if (!model.getLwtTopic().equals(ActivityConstants.empty) && !model.getLwtMessage().equals(ActivityConstants.empty)) {
            connOpts.setWill(model.getLwtTopic(), model.getLwtMessage().getBytes(), model.getLwtQos(), model.isLwtRetain());
        }
        /*if(!model.getDeviceSecret().equals(ActivityConstants.empty)){
            model.setDeviceSecret(model.getDeviceSecret());
        }*/
        //   if(tlsConnection){
        //       // TODO Add Keys to conOpts here
        //       //connOpts.setSocketFactory();
        //   }
        return connOpts;
    }


    public void connect(Connection connection) {
        String[] actionArgs = new String[1];
        actionArgs[0] = connection.getId();
        final ActionListener callback = new ActionListener(this,
                ActionListener.Action.CONNECT, connection, actionArgs);
        connection.getClient().setCallback(new MqttCallbackHandler(this, connection.handle()));
        try {
            connection.getClient().connect(connection.getConnectionOptions(), null, callback);
        } catch (MqttException e) {
            Log.e(this.getClass().getCanonicalName(),
                    "MqttException occurred", e);
        }
    }

    public void disconnect(Connection connection) {

        try {
            Log.d(TAG, "disconnect: MQTT 准备 断开连接");
            connection.getClient().disconnect();
        } catch (MqttException ex) {
            Log.e(TAG, "Exception occurred during disconnect: " + ex.getMessage());
        }
    }

    public void publish(Connection connection, String topic, String message, int qos, boolean retain) {

        try {
            String[] actionArgs = new String[2];
            actionArgs[0] = message;
            actionArgs[1] = topic;
            final ActionListener callback = new ActionListener(this,
                    ActionListener.Action.PUBLISH, connection, actionArgs);
            connection.getClient().publish(topic, message.getBytes(), qos, retain, null, callback);
        } catch (MqttException ex) {
            Log.e(TAG, "Exception occurred during publish: " + ex.getMessage());
        }
    }

    /**
     * This class ensures that the user interface is updated as the Connection objects change their states
     */
    private class ChangeListener implements PropertyChangeListener {

        /**
         * @see PropertyChangeListener#propertyChange(PropertyChangeEvent)
         */
        @Override
        public void propertyChange(PropertyChangeEvent event) {

            if (!event.getPropertyName().equals(ActivityConstants.ConnectionStatusProperty)) {
                return;
            }
            mainActivity.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    mainActivity.drawerFragment.notifyDataSetChanged();
                }

            });

        }

    }

}
